/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.core;
import java.util.*;
import java.io.*;
import java.net.URL;
import java.net.MalformedURLException;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.openide.TopManager;
import org.openide.modules.*;
/** ModuleInstallerSupport provides supporting methods for ModuleInstaller. It
* cares about writing/reading modules to/from XML. Maintains list of modules etc.
* check dependencies
*
* @author Administrator
* @version
*/
class ModuleInstallerSupport extends Object {
/** Extensions for modules in the folders */
private static final String JAR_EXT = ".jar"; // NOI18N
/** Installed enabled modules */
static final int ENABLED_MODULE = 1;
/** Installed disabled modules */
static final int DISABLED_MODULE = 2;
/** Deleted modules */
// static final int DELETED_MODULE = 4;
/** Modules for testing */
static final int TEST_MODULE = 8;
/** New modules added in autoload directory since last start */
static final int AUTOLOAD_CENTRAL_MODULE = 16;
/** New modules found in users autoload directory */
static final int AUTOLOAD_USER_MODULE = 32;
/** Patches - not used yet */
static final int PATCH = 64;
/** Central directory for modules */
private static File centralModuleDirectory = null;
/** User directory for modules */
private static File userModuleDirectory = null;
/** Name of file to contain stored modules */
private static final String INSTALLED_MODULES = "installedModules.xml"; // NOI18N
/** Map between module names and ModuleItems
* @associates ModuleItem*/
private HashMap nameModuleMap = new HashMap( 77 );
/** Enabled and disabled - installed modules
* @associates ModuleItem*/
private LinkedList installedModules = new LinkedList();
/** Modules for testing
* @associates ModuleItem*/
private LinkedList testModules = new LinkedList();
/** Modules deleted */
// private LinkedList deletedModules = new LinkedList();
/** Modules found in autoload director(ies)
* @associates ModuleItem*/
private LinkedList autoloadCentralModules = new LinkedList();
/** Modules found in local autoload directory
* @associates ModuleItem*/
private LinkedList autoloadUserModules = new LinkedList();
/** Creates new ModuleRegistry
*/
public ModuleInstallerSupport() {
try {
readRegistry();
}
catch ( java.io.IOException e ) {
// Do nothing - leave the registry empty
}
// System.out.println("Looking for new modules" );
findNewModules();
}
/** Gets the central directory of modules
*/
static File getCentralModuleDirectory() {
if ( centralModuleDirectory == null ) {
centralModuleDirectory = new File (Main.homeDir + File.separator + Main.DIR_MODULES);
}
return centralModuleDirectory;
}
/** Gets the user modules directory
*/
static File getUserModuleDirectory() {
if ( userModuleDirectory == null ) {
userModuleDirectory = new File (Main.userDir == null ? Main.homeDir : Main.userDir
+ File.separator + Main.DIR_MODULES);
}
return userModuleDirectory;
}
/** Gets all installed parts of given kind
*/
Collection get( int kind ) {
ArrayList result = new ArrayList();
// Standard modules
Iterator it = installedModules.iterator();
while( it.hasNext() ) {
ModuleItem mi = (ModuleItem) it.next();
if ( ( kind & ENABLED_MODULE ) > 0 && mi.isEnabled() ) {
result.add( mi );
}
else if ( ( kind & DISABLED_MODULE ) > 0 && !mi.isEnabled() ) {
result.add( mi );
}
}
// Test Modules
if ( ( kind & TEST_MODULE ) > 0 ) {
result.addAll( testModules );
}
// Deleted Modules
/*
if ( ( kind & DELETED_MODULE ) > 0 ) {
result.addAll( deletedModules );
}
*/
// Autoload Modules
if ( ( kind & AUTOLOAD_CENTRAL_MODULE ) > 0 ) {
result.addAll( autoloadCentralModules );
}
// AutloadLocal Modules
if ( ( kind & AUTOLOAD_USER_MODULE ) > 0 ) {
result.addAll( autoloadUserModules );
}
return result;
}
/** Adds module into right into specified collection */
void add( ModuleItem mi, int kind ) {
switch ( kind ) {
case ENABLED_MODULE:
case DISABLED_MODULE:
installedModules.add( mi );
break;
case TEST_MODULE:
testModules.add( mi );
break;
/*
case DELETED_MODULE:
deletedModules.add( mi );
break;
*/
case AUTOLOAD_CENTRAL_MODULE:
autoloadCentralModules.add( mi );
break;
case AUTOLOAD_USER_MODULE:
autoloadUserModules.add( mi );
break;
default:
return;
}
nameModuleMap.put( mi.getDescription().getCodeNameBase(), mi );
}
/** Removes module from given collection */
void remove( ModuleItem mi, int kind ) {
switch ( kind ) {
case ENABLED_MODULE:
case DISABLED_MODULE:
installedModules.remove( mi );
break;
case TEST_MODULE:
testModules.remove( mi );
break;
/*
case DELETED_MODULE:
deletedModules.remove( mi );
break;
*/
case AUTOLOAD_CENTRAL_MODULE:
autoloadCentralModules.remove( mi );
break;
case AUTOLOAD_USER_MODULE:
autoloadUserModules.remove( mi );
break;
default:
return;
}
nameModuleMap.remove( mi.getDescription().getCodeNameBase() );
}
/** Gets the kind of given module */
int getKind( ModuleItem mi ) {
ArrayList result = new ArrayList();
// Standard modules
if ( installedModules.contains( mi ) ) {
if ( mi.isEnabled() )
return ENABLED_MODULE;
else
return DISABLED_MODULE;
}
// Test Modules
if ( testModules.contains( mi ) ) {
return TEST_MODULE;
}
// Deleted Modules
/*
if ( deletedModules.contains( mi ) ) {
return DELETED_MODULE;
}
*/
// Autoload Central Modules
if ( autoloadCentralModules.contains( mi ) ) {
return AUTOLOAD_CENTRAL_MODULE;
}
// Autload Local Modules
if ( autoloadUserModules.contains( mi ) ) {
return AUTOLOAD_USER_MODULE;
}
return -1;
}
/** Gets installed part identified by it's key
*/
ModuleItem get( String key ) {
return (ModuleItem)nameModuleMap.get( key );
}
/** Writes the whole registry to XML file
*/
void writeRegistry() {
OutputStream os = null;
try {
os = new BufferedOutputStream (
new FileOutputStream ( new File ( getUserModuleDirectory(), INSTALLED_MODULES )));
new XML().write ( os );
}
catch ( IOException e ) {
TopManager.getDefault().notifyException( e );
}
finally {
if ( os != null )
try {
os.close ();
}
catch( IOException e ) {}
}
}
/** Reads the whole registry. The read of registry is not restricted to
* to reading of XML file, it also checks the module directory for newly
* installed modules (Autoload feature)
*/
void readRegistry() throws java.io.IOException {
File f = new File ( getUserModuleDirectory(), INSTALLED_MODULES);
InputStream is = new BufferedInputStream (new FileInputStream (f));
try {
new XML().read( f.toURL (), is );
}
finally {
is.close ();
}
}
/** Test's wether IDE is runs under multiuser installation */
static boolean isMultiuser() {
return !getUserModuleDirectory().equals( getCentralModuleDirectory() );
}
/** Loadsthe new modules from modules directory.
*/
void findNewModules() {
if ( isMultiuser() ) {
// In multiuser install first scan users directory
// System.out.println("Looking in USER" );
findModulesInFolder( getUserModuleDirectory(), AUTOLOAD_USER_MODULE );
}
// System.out.println("LOOKING iN CENTRAL" );
findModulesInFolder( getCentralModuleDirectory(), AUTOLOAD_CENTRAL_MODULE );
}
/** Finds all jars in given folder and loads them into collection specified by
* moduleType
* @param folder Folder to search
* @param moduleType Type of the module ( AUTOLOAD_CENTRAL_MODULE || AUTOLOAD_USER_MODULE )
*/
private void findModulesInFolder( File folder, int moduleType ) {
// System.out.println("Looking in : " + folder ); // NOI18N
if ( moduleType != AUTOLOAD_CENTRAL_MODULE && moduleType != AUTOLOAD_USER_MODULE ) {
throw new InternalError();
}
// Find all jarfiles in the folder
final String[] list = folder.list ( new FilenameFilter() {
public boolean accept( File dir, String name ) {
return name.toLowerCase().endsWith( JAR_EXT );
}
} );
if ( list == null || list.length == 0 )
return;
// Go through the list and add ModuleItems into the collection
for ( int i = 0; i < list.length; i++ ) {
try {
ModuleItem mi = new ModuleItem (
moduleType == AUTOLOAD_CENTRAL_MODULE ? ModuleItem.BASE_CENTRAL : ModuleItem.BASE_USER,
list[i],
true);
ModuleItem existing = get( mi.getDescription().getCodeNameBase() );
if ( existing != null ) { // The module already exists
int kind = getKind( existing );
switch ( kind ) {
case ENABLED_MODULE:
case DISABLED_MODULE:
// System.out.print(" Module mismatch " + mi.getDescription().getCodeNameBase() );
// System.out.println(" : " + existing.getBase() + " : " + mi.getBase() );
//case DELETED_MODULE:
if ( ( existing.getBase() != ModuleItem.BASE_CENTRAL &&
existing.getBase() != ModuleItem.BASE_USER ) ||
( existing.getBase() == ModuleItem.BASE_CENTRAL &&
mi.getBase() == ModuleItem.BASE_USER ) ||
( existing.getBase() == ModuleItem.BASE_USER &&
mi.getBase() == ModuleItem.BASE_CENTRAL )) {
// If there is a new module update the new module.
// System.out.println(" Module mismatch " + mi.getDescription().getCodeNameBase() );
mi.setOldRelease( existing.getOldRelease() );
mi.setOldSpecVersion( existing.getOldSpecVersion() );
if ( mi.isUpdated() ) {
remove( existing, kind );
add( mi, kind );
}
}
continue; // Standard behavior the module is already loaded from XML
case TEST_MODULE:
// Do nothing the test module goes first
continue;
case AUTOLOAD_USER_MODULE:
case AUTOLOAD_CENTRAL_MODULE:
// [ PENDING Show it to user ]
// System.out.println("AUTOLOAD Modules colision" ); // NOI18N
continue;
}
}
else { // If the module does not exists add it into new modules collection
add( mi, moduleType );
}
}
catch (IOException e) {
// wrong module
TopManager.getDefault ().notifyException (e);
}
}
}
/** Returns all modules of given kind depending on module
*/
Collection getDependentModules( ModuleDescription md, int kind ) {
Collection result = new ArrayList();
getDependentModules( md, kind, result );
return result;
}
/** Private/recursive method for retrieving dependencies
*/
private void getDependentModules( ModuleDescription md, int kind, Collection result ) {
Collection modules = get( kind );
//ModuleItem[] ims = getModuleItems( miSupport.ENABLED_MODULE );
Iterator it = modules.iterator();
//for( int j = 0; j < ims.length; j ++ ) {
while ( it.hasNext() ) {
//ModuleDescription imd = ims[j].getDescription();
ModuleItem mi = (ModuleItem)it.next();
ModuleDescription imd = mi.getDescription();
if ( result.contains( mi ) || md == imd ) {
continue;
}
if ( md.getCodeNameBase().equals( imd.getCodeNameBase() ) ) {
continue;
}
ModuleDescription.Dependency[] deps = imd.getDependencies();
for( int k = 0; k < deps.length; k++ ) {
if ( deps[k].getName().equals ( md.getCodeName ()) ) {
if ( !result.contains( mi ) ) {
result.add( mi );
getDependentModules( imd, kind, result );
}
}
}
}
}
/** Checks for dependencies on disabled modules. If the module depends on
* some disabled modules then the method returns collection of modules which
* should be enabled. If there are some other unsatisfied dependencies or
* no problems it returns null.
*/
Collection checkDependenciesOnDisabled( ModuleDescription md ) {
Collection result = new ArrayList( 10 );
return checkDependenciesOnDisabled( md, result ) ? result : null;
}
Collection checkDependenciesOnDisabled( Collection moduleItems ) {
Collection result = new ArrayList( 10 );
Iterator it = moduleItems.iterator();
while( it.hasNext() ) {
ModuleDescription md = ((ModuleItem)it.next()).getDescription();
if ( !checkDependenciesOnDisabled( md, result ) )
return null;
}
return result;
}
private boolean checkDependenciesOnDisabled( ModuleDescription md, Collection result ) {
ModuleDescription[] otherModules = ModuleInstaller.getModuleDescriptions(
ENABLED_MODULE | DISABLED_MODULE );
ModuleDescription.Dependency[] deps = md.getDependencies();
for ( int i = 0; i < deps.length; i++ ) {
String miss = null;
try {
miss = deps[i].checkForMiss (otherModules);
}
catch ( IllegalModuleException e ) {
return false;
}
if ( miss != null) {
return false; // Some dependencies are not satisfied
}
else if ( deps[i].getType() != ModuleDescription.Dependency.TYPE_MODULE ) {
continue;
}
else {
// Dependency is satisfied lets look if the module is enabled
String moduleName = deps[i].getName();
int index = moduleName.lastIndexOf( '/' );
if ( index == -1 ) {
index = moduleName.length();
}
ModuleItem dm = get( moduleName.substring( 0, index ) );
if ( getKind( dm ) == DISABLED_MODULE && !result.contains( dm ) ) {
result.add( dm );
if ( !checkDependenciesOnDisabled( dm.getDescription(), result ) )
return false;
}
}
}
return true;
}
// InnerClasses -----------------------------------------------------------
/** XML writes and reads all modules to / from XML.
*/
private class XML extends HandlerBase {
/** base URL */
private URL base;
/** Write the document to stream.
* @param os output stream
* @param list of ModuleItems
* @exception IOException if I/O error occured
*/
void write( OutputStream os ) throws IOException {
Collection list = get( ENABLED_MODULE | DISABLED_MODULE /* | DELETED_MODULE */ | TEST_MODULE );
PrintStream p = new PrintStream( os );
p.print( ModuleTags.XML_HEADER );
p.print( ModuleTags.NEW_LINE + ModuleTags.NEW_LINE );
p.print( ModuleTags.MODULES_HEADER );
p.print( ModuleTags.NEW_LINE );
Iterator it = list.iterator ();
while (it.hasNext ()) {
ModuleItem mi = (ModuleItem)it.next ();
p.print( mi.toXML() );
p.print( ModuleTags.NEW_LINE );
}
p.print( ModuleTags.MODULES_FOOTER );
p.print( ModuleTags.NEW_LINE );
p.close ();
}
/** Parse the input stream.
* @param url the base URL to referer all relative to
* @return list of ModuleItems
* @exception IOException if I/O error occured
*/
void read( URL url, InputStream is ) throws IOException {
base = url;
Parser p = org.openide.loaders.XMLDataObject.createParser ();
p.setDocumentHandler ( this );
try {
p.parse (new InputSource (is));
} catch (SAXException e) {
throw new IOException (e.getMessage ());
}
return;
}
/** Creates new XML parser/saver for given list of ModuleItems.
*/
XML () {
}
/** Creates the right type of module item and adds it to list of modules.
*/
public void startElement (String name, AttributeList attr) {
if ( name.equals( ModuleTags.MODULE ) ) {
ModuleItem mi = ModuleItem.fromXML( attr, base );
if ( mi != null ) {
/* if ( mi.isDeleted() )
add( mi, ModuleInstallerSupport.DELETED_MODULE );
else */ if ( mi.isEnabled() )
add( mi, ModuleInstallerSupport.ENABLED_MODULE );
else
add( mi, ModuleInstallerSupport.DISABLED_MODULE );
}
}
else if ( name.equals( ModuleTags.TEST_MODULE ) ) {
TestModuleItem tmi = TestModuleItem.fromXML( attr );
if ( tmi != null ) {
add( tmi, ModuleInstallerSupport.TEST_MODULE );
}
}
}
}
public String toString() {
StringBuffer sb = new StringBuffer( 500 );
sb.append("ENABLED --------------------------\n" ); // NOI18N
sb.append( modulesToString( get( ModuleInstallerSupport.ENABLED_MODULE ) ) );
sb.append( "\n" ); // NOI18N
sb.append("DISABLED --------------------------\n" ); // NOI18N
sb.append( modulesToString( get( ModuleInstallerSupport.DISABLED_MODULE ) ) );
sb.append( "\n" ); // NOI18N
/*
sb.append("DELETED --------------------------\n" ); // NOI18N
sb.append( modulesToString( get( ModuleInstallerSupport.DELETED_MODULE ) ) );
*/
sb.append( "\n" ); // NOI18N
sb.append("TEST --------------------------\n" ); // NOI18N
sb.append( modulesToString( get( ModuleInstallerSupport.TEST_MODULE ) ) );
sb.append( "\n" ); // NOI18N
sb.append("CENTRAL --------------------------\n" ); // NOI18N
sb.append( modulesToString( get( ModuleInstallerSupport.AUTOLOAD_CENTRAL_MODULE ) ) );
sb.append( "\n" ); // NOI18N
sb.append("USER --------------------------\n" ); // NOI18N
sb.append( modulesToString( get( ModuleInstallerSupport.AUTOLOAD_USER_MODULE ) ) );
sb.append( "\n" ); // NOI18N
return sb.toString();
}
String modulesToString( Collection modules ) {
StringBuffer sb = new StringBuffer( 100 );
Iterator it = modules.iterator();
while( it.hasNext() ) {
ModuleItem mi = (ModuleItem)it.next();
sb.append( " " + mi.getDescription().getName() + mi.getLoaderURL() ); // NOI18N
sb.append( "\n" ); // NOI18N
}
return sb.toString();
}
}
/*
* Log
*/